import React, { useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import Empty from '../Empty/index';
import Button from '../Button';
import './virtual.scss';

const VirtualList = (props) => {
  // 所有的数据(很多很多哦)
  const { dataSource, listRender, getChildHeight } = props;
  // 偏移 [0,0] 主要是取值
  const [position, setPosition] = useState([0, 0]);
  const box = React.useRef(null); /* 获取元素用于容器高度 */
  const itemBoxRef = React.useRef(null); /* 用户获取子元素item的高度 */
  // 存储一些常规的数据
  const virtualInfo = React.useRef({
    itemHeight: 60, // 初始化的时候根据渲染的高度获取
    bufferCount: 8,
    renderCount: 0, // 数据列表中可渲染的数据个数
  });

  // 获取数据
  function init() {
    const { itemHeight, bufferCount } = virtualInfo.current;
    const height = box.current.offsetHeight;
    // 计算当前容器能容纳多少item  父组件的高度 / item的高度 + 缓冲区容纳个数
    const renderCount = Math.ceil(height / itemHeight) + bufferCount;
    // 存起来
    virtualInfo.current = {
      renderCount,
      height,
      itemHeight,
      bufferCount,
    };
    // 初始数据偏移量为 0 - 可容纳数量
    setPosition([0, renderCount]);
  }

  // 滚动改变迁移
  const handleScroll = () => {
    const { scrollTop } = box.current;
    const { itemHeight, bufferCount, renderCount } = virtualInfo.current;
    // 检测滚动了几个偏移量
    const currentOffset = scrollTop - (scrollTop % itemHeight);
    // 检测当前滚动的值,超过了几个item  0-120 表示已经滚动超出了两个item
    // 然后将超出的item的下标,变成重新开始的start [121px为第三个模块],
    const start = Math.floor(scrollTop / itemHeight);
    /* 偏移，造成下滑效果 */
    itemBoxRef.current.style.transform = `translate3d(0, ${currentOffset}px, 0)`;
    // 计算偏移后的end
    const end = start + renderCount;
    // console.log('start ===> ', start, 'end ===> ', end);
    // 如果偏移量没改变 表示当前的虚拟滚动没有滑完
    if (position[0] !== start || position[1] !== end) {
      setPosition([start, end]);
      getChildHeight({
        position: [start, end],
      });
    }
  };

  useEffect(() => {
    init();
  }, []);

  useEffect(() => {
    // 计算每一个item的高度
    const itemInfo = itemBoxRef.current.childNodes;
    console.log('itemInfo ===> ', itemInfo);
    if (itemInfo.length) {
      virtualInfo.current.itemHeight = itemInfo[0].offsetHeight;
      getChildHeight({
        itemHeight: itemInfo[0].offsetHeight,
      });
    }
  }, [dataSource]);

  // 计算虚拟列表元素的承载元素高度 (总数据长度 * item高度)
  const itemFatherBox = useCallback(() => {
    if (dataSource.length) {
      return dataSource.length * virtualInfo.current.itemHeight + 'px';
    }
    return 'auto';
  }, [dataSource, virtualInfo]);

  // 根据区间渲染数据
  const [start, end] = position;
  const renderList = dataSource.slice(start, end); /* 渲染区间 */

  return (
    // 滚动容器,承载着滚动的元素
    <>
      <div className="virtual-container" ref={box} onScroll={handleScroll}>
        {/* 虚拟列表的高度要根据数据量来进行判断 */}
        <div className="virtual-box" style={{ height: itemFatherBox() }}>
          <div ref={itemBoxRef}>
            {renderList.length ? renderList.map(listRender) : <Empty />}
          </div>
        </div>
      </div>
    </>
  );
};

// props 约束
VirtualList.defaultProps = {
  // 数据源
  dataSource: PropTypes.array,
  // 自定义渲染
  listRender: PropTypes.func,
  // 获取渲染后后单个子元素的高度
  getChildHeight: PropTypes.func,
};

export default VirtualList;
